package edu.hawaii.halealohacli.command;

import java.util.Calendar;
import java.util.Formatter;
import java.util.GregorianCalendar;
import java.util.Locale;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.client.WattDepotClientException;
import org.wattdepot.resource.sensordata.jaxb.SensorData;

/**
 * Retrieves the most recent data on how much power is being consumed by a particular source.
 * 
 * @author Andrea Connell
 * @author Zach Tomaszewski
 */
public class CurrentPower implements Command {

  private String sourceName;
  private WattDepotClient client;
  private boolean valid = false;

  /**
   * Expects a single argument representing the name of the source to find current power for.
   * 
   * @param args A string array containing the name of the source to collect data from.
   * @param client The WattDepot client to collect this data from.
   * 
   */
  @Override
  public void initialize(String[] args, WattDepotClient client) {
    this.client = client;
    this.valid = (args.length == 1);
    if (this.valid) {
      this.sourceName = args[0];
    }
  }

  /**
   * Prints the returned value from getResults to System.out.
   */
  @Override
  public void execute() {
    System.out.println(getResults());
  }

  /**
   * Finds the amount of power being used by this source and returns it in string format.
   * 
   * @return A string representing the amount of power being used, or the error that occurred.
   */
  public String getResults() {

    try {
      Data data = this.getCurrentPower();
      if (data.getLatency() / 1000 > 60 * 6) {
        return "Sensor Data for " + sourceName + " has a latency over 6 minutes.";
      }

      Formatter formatter = new Formatter(new StringBuilder(), Locale.US);
      return formatter.format("%1$s's power as of %2$tF %2$tT was %3$.1fkW", 
          data.getSource(), data.getTimestamp(), data.getPower() / 1000).toString();
    }
    catch (IllegalStateException e) {
      return e.getMessage();
    }
    catch (ResourceNotFoundException e) {
      return sourceName + " is not a valid source name.";
    }
    catch (WattDepotClientException e) {
      return "Sensor data could not be retrieved for " + sourceName;
    }
  }
  
  /**
   * Returns the current power data using the source and client with which
   * this CurrentPower object was initialized.  
   * 
   * @return  The most recent power data
   * @throws WattDepotClientException  if there is a problem retrieving the data
   * @throws IllegalStateException  if this CommandPower object is not
   *            properly initialized; the contained message may be printed to a user.
   */
  public CurrentPower.Data getCurrentPower() throws WattDepotClientException {
    //check state of this command
    if (client == null || !client.isHealthy()) {
      throw new IllegalStateException("Invalid WattDepot client");
    }
    else if (!valid) {
      throw new IllegalStateException("Invalid arguments for " + getCommandName() + 
          ".\n" + getCommandUsage());
    }
    
    SensorData data = client.getLatestSensorData(sourceName);
    Double power = Double.valueOf(data.getProperty(SensorData.POWER_CONSUMED));
    GregorianCalendar time = data.getTimestamp().toGregorianCalendar();
    return new Data(sourceName, power, time);    
  }
  
  @Override
  public String getCommandName() {
    return "current-power";
  }

  @Override
  public String getCommandUsage() {
    return getCommandName()
        + " [tower | lounge]\nReturns the current power in kW for the"
        + " associated tower or lounge.\n\n";
  }
  
  /**
   * An immutable snapshot of a source's most recent power consumption data.
   * Includes the source name, the time the data was recorded on the server,
   * and the latency compared to the current time.
   *  
   * @see CurrentPower#getCurrentPower()  
   */
  protected static class Data {
    
    private String source;
    private double power;
    private Calendar timestamp;
        
    /**
     * Constructs a new Data object.
     * 
     * @param source  The name of the source of this data
     * @param power   The source's power consumption in kw
     * @param timestamp  When this data was recorded on the server
     */
    protected Data(String source, double power, Calendar timestamp) {
      this.source = source;
      this.power = power;
      this.timestamp = (Calendar) timestamp.clone();
    }

    /**
     * Returns the name of the source of this data.
     * 
     * @return  The source's name
     */
    public String getSource() {
      return source;
    }
    
    /**
     * Returns the source's power consumption in watts.
     * 
     * @return  Power in watts
     */
    public double getPower() {
      return power;
    }
    
    /**
     * Returns the time at which this data was recorded by the server.
     * 
     * @return  A copy of this data's timestamp
     */
    public Calendar getTimestamp() {
      return (Calendar) timestamp.clone();
    }
    
    /**
     * Computes the length of time in milliseconds between this data's
     * timestamp and the current local time.
     * 
     * @return  The latency in ms
     */
    public long getLatency() {
      long now = Calendar.getInstance(Locale.US).getTimeInMillis();
      return now - timestamp.getTimeInMillis();      
    }
  }

}
